﻿// Project1.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "Project1.h"

#include <iostream>
#include <vector>

#include <cstdint>
#include <comdef.h>






#include "向量.h"
#include <wrl.h>
#include <wrl/client.h>
#include <dxgi1_4.h>
#include <d3d12.h>

#include <windows.h>
#include <wrl.h>
#include <dxgi1_4.h>
#include <d3d12.h>
#include <D3Dcompiler.h>
#include <DirectXMath.h>
#include <DirectXPackedVector.h>
#include <DirectXColors.h>
#include <DirectXCollision.h>
#include <string>
#include <memory>
#include <algorithm>
#include <vector>
#include <array>
#include <unordered_map>
#include <cstdint>
#include <fstream>
#include <sstream>
#include <cassert>


#include <pix.h>
#include <DirectXColors.h>


#if defined(_DEBUG)
#include <dxgidebug.h>
#endif


using namespace Microsoft::WRL;
using namespace std;









#pragma comment(lib, "d3dcompiler.lib")
#pragma comment(lib, "D3D12.lib")
#pragma comment(lib, "dxgi.lib")






ComPtr<ID3D12RootSignature>		g_RootSignature;
ComPtr<IDXGIFactory4>			g_mdxgiFactory;

ComPtr<ID3D12CommandAllocator>		g_DirectCmdListAlloc;
ComPtr<ID3D12CommandQueue>			g_命令列队;
ComPtr<ID3D12GraphicsCommandList>	g_命令列表;


//static ComPtr<ID3D12DescriptorHeap>	g_RtvHeap;
static ComPtr<ID3D12DescriptorHeap>	g_DsvHeap;


static DXGI_FORMAT					g_渲染图像格式 = DXGI_FORMAT_R8G8B8A8_UNORM;
static uint8						g_交换链缓存数量 = 3;
static uint8						g_m4xMsaaQuality = 0;




DXGI_FORMAT mBackBufferFormat		= DXGI_FORMAT_R8G8B8A8_UNORM;
DXGI_FORMAT mDepthStencilFormat		= DXGI_FORMAT_D24_UNORM_S8_UINT;




ID3D12Device1*	m_设备;
IDXGIAdapter*	m_pWarpAdapter;
ID3D12Fence*	m_Fence;

ComPtr<IDXGISwapChain>		m_交换链;
ComPtr<IDXGISwapChain1>		m_交换链1;
IDXGISwapChain3*			m_交换链3;

vector<ComPtr<ID3D12Resource>>	m_交换链缓存;
ComPtr<ID3D12Resource>			m_DepthStencilBuffer;


uint64			m_CurrentFence;
uint32			m_CurrBackBuffer;

uint32			m_RTV_size;
uint32			m_DSV_size;
uint32			m_CbvUav_size;


D3D12_VIEWPORT	m_视口;
D3D12_RECT		m_裁剪;



// Heap data
struct HeapData {
	ComPtr<ID3D12DescriptorHeap> pHeap;
	uint32_t usedEntries = 0;
};
HeapData m_渲染目标视图堆;








void GetHardwareAdapter(IDXGIAdapter1** ppAdapter)
{
	ComPtr<IDXGIAdapter1> adapter;
	*ppAdapter = nullptr;

	for (UINT adapterIndex = 0; DXGI_ERROR_NOT_FOUND != g_mdxgiFactory->EnumAdapters1(adapterIndex, &adapter); adapterIndex++)
	{
		DXGI_ADAPTER_DESC1 desc;
		adapter->GetDesc1(&desc);

		if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
		{
			// 不要选择基本呈现驱动程序适配器。
			continue;
		}

		// 检查适配器是否支持 Direct3D 12，但不要创建
		// 仍为实际设备。
		if (SUCCEEDED(D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr)))
		{
			break;
		}
	}

	*ppAdapter = adapter.Detach();
}





inline std::wstring AnsiToWString(const std::string& str)
{
	WCHAR buffer[512];
	MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, buffer, 512);
	return std::wstring(buffer);
}

#ifndef ThrowIfFailed
#define ThrowIfFailed(x)                                              \
{                                                                     \
    HRESULT hr__ = (x);                                               \
    std::wstring wfn = AnsiToWString(__FILE__);                       \
    if(FAILED(hr__)) { throw DxException(hr__, L#x, wfn, __LINE__); } \
}
#endif



class DxException
{
public:
	DxException() = default;
	DxException(HRESULT hr, const std::wstring& functionName, const std::wstring& filename, int lineNumber) :
		ErrorCode(hr),
		FunctionName(functionName),
		Filename(filename),
		LineNumber(lineNumber) {

	}

	std::wstring ToString()const {
		// Get the string description of the error code.
		_com_error err(ErrorCode);
		std::wstring msg = err.ErrorMessage();

		return FunctionName + L" failed in " + Filename + L"; line " + std::to_wstring(LineNumber) + L"; error: " + msg;
	}

	HRESULT ErrorCode = S_OK;
	std::wstring FunctionName;
	std::wstring Filename;
	int LineNumber = -1;
};









#define MAX_LOADSTRING 100

// 全局变量:
HINSTANCE hInst;                                // 当前实例
WCHAR szTitle[MAX_LOADSTRING];                  // 标题栏文本
WCHAR szWindowClass[MAX_LOADSTRING];            // 主窗口类名

// 此代码模块中包含的函数的前向声明:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: 在此处放置代码。

    // 初始化全局字符串
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_PROJECT1, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // 执行应用程序初始化:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PROJECT1));

    MSG msg;



    // 主消息循环:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}



//
//  函数: MyRegisterClass()
//
//  目标: 注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PROJECT1));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_PROJECT1);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

//
//   函数: InitInstance(HINSTANCE, int)
//
//   目标: 保存实例句柄并创建主窗口
//
//   注释:
//
//        在此函数中，我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // 将实例句柄存储在全局变量中

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);











	#ifdef _DEBUG 
	{
		ComPtr<ID3D12Debug> debug控制;
		ThrowIfFailed(D3D12GetDebugInterface(IID_PPV_ARGS(&debug控制)));
		debug控制->EnableDebugLayer();

	}
	#endif

	ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&g_mdxgiFactory)));
	//g_mdxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(&m_pWarpAdapter));

	//ComPtr<IDXGIAdapter1> adapter;
	//GetHardwareAdapter(&adapter);

	HRESULT hardware = D3D12CreateDevice(0, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_设备));
	if (FAILED(hardware)) {
		cout << "创建DX设备失败" << endl;
	}

	// Fallback to WARP device.
	if (FAILED(hardware)) {
		ComPtr<IDXGIAdapter> pWarpAdapter;
		ThrowIfFailed(g_mdxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(&pWarpAdapter)));

		ThrowIfFailed(D3D12CreateDevice(pWarpAdapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_设备)));
	}



	//m_设备->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_Fence));
	ThrowIfFailed(m_设备->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_Fence)));
	//gDirectCmdListAlloc
	m_RTV_size = m_设备->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
	m_DSV_size = m_设备->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
	m_CbvUav_size = m_设备->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);




	D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS ms质量等级;
	ms质量等级.Format = DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_UNORM;
	ms质量等级.SampleCount = 4;
	ms质量等级.Flags = D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE;
	ms质量等级.NumQualityLevels = 0;
	ThrowIfFailed(m_设备->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &ms质量等级, sizeof(ms质量等级)));
	g_m4xMsaaQuality = ms质量等级.NumQualityLevels;








	UINT i = 0;
	IDXGIAdapter* adapter = nullptr;
	std::vector<IDXGIAdapter*> adapterList;
	while (g_mdxgiFactory->EnumAdapters(i, &adapter) != DXGI_ERROR_NOT_FOUND) {
		DXGI_ADAPTER_DESC desc;
		adapter->GetDesc(&desc);

		std::wstring text = L"***Adapter: ";
		text += desc.Description;
		text += L"\n";

		OutputDebugString(text.c_str());

		adapterList.push_back(adapter);

		++i;
	}

	








	D3D12_COMMAND_QUEUE_DESC queuedesc = {};
	ZeroMemory(&queuedesc, sizeof(queuedesc));
	queuedesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
	queuedesc.Priority = 0;
	queuedesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
	queuedesc.NodeMask = 0;

	ThrowIfFailed(m_设备->CreateCommandQueue(&queuedesc, IID_PPV_ARGS(&g_命令列队)));
	ThrowIfFailed(m_设备->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(g_DirectCmdListAlloc.GetAddressOf())));
	
	ThrowIfFailed(m_设备->CreateCommandList(
		0,
		D3D12_COMMAND_LIST_TYPE_DIRECT,
		g_DirectCmdListAlloc.Get(),
		0,
		IID_PPV_ARGS(g_命令列表.GetAddressOf())
	));

	g_命令列表->Close();



	ivec2 size = {1024, 576};


	m_交换链.Reset();

	DXGI_SWAP_CHAIN_DESC sd;
	sd.BufferDesc.Width = size.x;
	sd.BufferDesc.Height = size.y;
	sd.BufferDesc.RefreshRate.Numerator = 60;
	sd.BufferDesc.RefreshRate.Denominator = 1;
	sd.BufferDesc.Format = mBackBufferFormat;
	sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
	sd.SampleDesc.Count = 1 ? 4 : 1;
	sd.SampleDesc.Quality = 1 ? (g_m4xMsaaQuality - 1) : 0;
	sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	sd.BufferCount = g_交换链缓存数量;
	sd.OutputWindow = hWnd;
	sd.Windowed = true;
	sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
	sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

	ThrowIfFailed(g_mdxgiFactory->CreateSwapChain(g_命令列队.Get(), &sd, m_交换链.GetAddressOf()));



	if (1) {
		DXGI_SWAP_CHAIN_DESC1 sd1 = {};
		SecureZeroMemory(&sd1, sizeof(sd1));

		sd1.Width = size.x;
		sd1.Height = size.y;

		sd1.Format = g_渲染图像格式;
		sd1.Scaling = DXGI_SCALING_STRETCH;
		sd1.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT;
		sd1.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
		sd1.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
		sd1.SampleDesc.Count = 1 ? 4 : 1;
		sd1.SampleDesc.Quality = 1 ? (g_m4xMsaaQuality - 1) : 0;
		sd1.Flags = 0;

		sd1.BufferCount = g_交换链缓存数量;



		ThrowIfFailed(g_mdxgiFactory->CreateSwapChainForHwnd(g_命令列队.Get(), hWnd, &sd1, 0, 0, m_交换链1.GetAddressOf()));
		
		ThrowIfFailed(m_交换链->QueryInterface(IID_PPV_ARGS(&m_交换链3)));
		
	}


	/*m_交换链.Reset();

	DXGI_SWAP_CHAIN_DESC sd = {};
	ZeroMemory(&sd, sizeof(sd));
	sd.BufferDesc.Width = size.x;
	sd.BufferDesc.Height = size.y;
	sd.BufferDesc.RefreshRate.Numerator = 60;
	sd.BufferDesc.RefreshRate.Denominator = 1;
	sd.BufferDesc.Format = g_渲染图像格式;
	sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
	sd.SampleDesc.Count = 1 ? 4 : 1;
	sd.SampleDesc.Quality = 1 ? (g_m4xMsaaQuality - 1) : 0;
	sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	sd.BufferCount = g_交换链缓存数量;
	sd.OutputWindow = hWnd;
	sd.Windowed = true;
	sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
	sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

	ComPtr<IDXGISwapChain>		m_交换链A;
	ThrowIfFailed(g_mdxgiFactory->CreateSwapChain(g_命令列队.Get(), &sd, m_交换链A.GetAddressOf()));*/



	return TRUE;
}

//
//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目标: 处理主窗口的消息。
//
//  WM_COMMAND  - 处理应用程序菜单
//  WM_PAINT    - 绘制主窗口
//  WM_DESTROY  - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // 分析菜单选择:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: 在此处添加使用 hdc 的任何绘图代码...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}
